Sensor Fusion for Kinetis MCUs (ISSDK/KSDK version)
orientation.c File Reference
+ Include dependency graph for orientation.c:

Go to the source code of this file.

Macros

#define SMALLQ0   1E-4F
 
#define CORRUPTQUAT   0.001F
 
#define SMALLMODULUS   0.01F
 

Functions

void f3DOFMagnetometerMatrixNED (float fR[][3], float fBc[])
 
void f3DOFMagnetometerMatrixAndroid (float fR[][3], float fBc[])
 
void f3DOFMagnetometerMatrixWin8 (float fR[][3], float fBc[])
 
void feCompassNED (float fR[][3], float *pfDelta, float *pfsinDelta, float *pfcosDelta, float fBc[], float fGc[], float *pfmodBc, float *pfmodGc)
 
void feCompassAndroid (float fR[][3], float *pfDelta, float *pfsinDelta, float *pfcosDelta, float fBc[], float fGc[], float *pfmodBc, float *pfmodGc)
 
void feCompassWin8 (float fR[][3], float *pfDelta, float *pfsinDelta, float *pfcosDelta, float fBc[], float fGc[], float *pfmodBc, float *pfmodGc)
 
void fNEDAnglesDegFromRotationMatrix (float R[][3], float *pfPhiDeg, float *pfTheDeg, float *pfPsiDeg, float *pfRhoDeg, float *pfChiDeg)
 
void fAndroidAnglesDegFromRotationMatrix (float R[][3], float *pfPhiDeg, float *pfTheDeg, float *pfPsiDeg, float *pfRhoDeg, float *pfChiDeg)
 
void fWin8AnglesDegFromRotationMatrix (float R[][3], float *pfPhiDeg, float *pfTheDeg, float *pfPsiDeg, float *pfRhoDeg, float *pfChiDeg)
 
void fQuaternionFromRotationVectorDeg (Quaternion *pq, const float rvecdeg[], float fscaling)
 
void fQuaternionFromRotationMatrix (float R[][3], Quaternion *pq)
 
void fRotationMatrixFromQuaternion (float R[][3], const Quaternion *pq)
 
void fRotationVectorDegFromQuaternion (Quaternion *pq, float rvecdeg[])
 
void fLPFOrientationQuaternion (Quaternion *pq, Quaternion *pLPq, float flpf, float fdeltat, float fOmega[])
 
void qAeqBxC (Quaternion *pqA, const Quaternion *pqB, const Quaternion *pqC)
 
void qAeqAxB (Quaternion *pqA, const Quaternion *pqB)
 
Quaternion qconjgAxB (const Quaternion *pqA, const Quaternion *pqB)
 
void fqAeqNormqA (Quaternion *pqA)
 
void fqAeq1 (Quaternion *pqA)
 
void fveqconjgquq (Quaternion *pfq, float fu[], float fv[])
 

Detailed Description

Functions to convert between various orientation representations. Also includes functions for manipulating quaternions.

Definition in file orientation.c.

Macro Definition Documentation

#define CORRUPTQUAT   0.001F

Definition at line 52 of file orientation.c.

Referenced by fqAeqNormqA().

#define SMALLMODULUS   0.01F

Definition at line 53 of file orientation.c.

#define SMALLQ0   1E-4F

Definition at line 51 of file orientation.c.

Referenced by fQuaternionFromRotationMatrix().

Function Documentation

void f3DOFMagnetometerMatrixAndroid ( float  fR[][3],
float  fBc[] 
)

Android magnetometer 3DOF flat eCompass function, computing rotation matrix fR.

Parameters
fRcomputed rotation matrix (output)
fBccalibrated magnetometer reading (input)

Definition at line 245 of file orientation.c.

Referenced by f3DOFMagnetometerMatrixWin8(), fInit_3DOF_B_BASIC(), and fRun_3DOF_B_BASIC().

246 {
247  // local variables
248  float fmodBxy; // modulus of the x, y magnetometer readings
249 
250  // compute the magnitude of the horizontal (x and y) magnetometer reading
251  fmodBxy = sqrtf(fBc[CHX] * fBc[CHX] + fBc[CHY] * fBc[CHY]);
252 
253  // check for zero field special case where no solution is possible
254  if (fmodBxy == 0.0F)
255  {
256  f3x3matrixAeqI(fR);
257  return;
258  }
259 
260  // define the fixed entries in the z row and column
261  fR[CHZ][CHX] = fR[CHZ][CHY] = fR[CHX][CHZ] = fR[CHY][CHZ] = 0.0F;
262  fR[CHZ][CHZ] = 1.0F;
263 
264  // define the remaining entries
265  fR[CHX][CHX] = fR[CHY][CHY] = fBc[CHY] / fmodBxy;
266  fR[CHX][CHY] = fBc[CHX] / fmodBxy;
267  fR[CHY][CHX] = -fR[CHX][CHY];
268 
269  return;
270 }
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:77
#define CHZ
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
void f3x3matrixAeqI(float A[][3])
function sets the 3x3 matrix A to the identity matrix
Definition: matrix.c:45

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void f3DOFMagnetometerMatrixNED ( float  fR[][3],
float  fBc[] 
)

Aerospace NED magnetometer 3DOF flat eCompass function, computing rotation matrix fR.

Parameters
fRcomputed rotation matrix (output)
fBccalibrated magnetometer reading (input)

Definition at line 215 of file orientation.c.

Referenced by fInit_3DOF_B_BASIC(), and fRun_3DOF_B_BASIC().

216 {
217  // local variables
218  float fmodBxy; // modulus of the x, y magnetometer readings
219 
220  // compute the magnitude of the horizontal (x and y) magnetometer reading
221  fmodBxy = sqrtf(fBc[CHX] * fBc[CHX] + fBc[CHY] * fBc[CHY]);
222 
223  // check for zero field special case where no solution is possible
224  if (fmodBxy == 0.0F)
225  {
226  f3x3matrixAeqI(fR);
227  return;
228  }
229 
230  // define the fixed entries in the z row and column
231  fR[CHZ][CHX] = fR[CHZ][CHY] = fR[CHX][CHZ] = fR[CHY][CHZ] = 0.0F;
232  fR[CHZ][CHZ] = 1.0F;
233 
234  // define the remaining entries
235  fR[CHX][CHX] = fR[CHY][CHY] = fBc[CHX] / fmodBxy;
236  fR[CHY][CHX] = fBc[CHY] / fmodBxy;
237  fR[CHX][CHY] = -fR[CHY][CHX];
238 
239  return;
240 }
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:77
#define CHZ
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
void f3x3matrixAeqI(float A[][3])
function sets the 3x3 matrix A to the identity matrix
Definition: matrix.c:45

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void f3DOFMagnetometerMatrixWin8 ( float  fR[][3],
float  fBc[] 
)

Windows 8 magnetometer 3DOF flat eCompass function, computing rotation matrix fR.

Parameters
fRcomputed rotation matrix (output)
fBccalibrated magnetometer reading (input)

Definition at line 275 of file orientation.c.

Referenced by fInit_3DOF_B_BASIC(), and fRun_3DOF_B_BASIC().

276 {
277  // call the Android function since it is identical to the Windows 8 matrix
279 
280  return;
281 }
void f3DOFMagnetometerMatrixAndroid(float fR[][3], float fBc[])
Android magnetometer 3DOF flat eCompass function, computing rotation matrix fR.
Definition: orientation.c:245

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void fAndroidAnglesDegFromRotationMatrix ( float  R[][3],
float *  pfPhiDeg,
float *  pfTheDeg,
float *  pfPsiDeg,
float *  pfRhoDeg,
float *  pfChiDeg 
)

extract the Android angles in degrees from the Android rotation matrix

Parameters
Rrotation matrix input
pfPhiDegthe roll angle -90.0 <= Phi <= 90.0 deg
pfTheDegthe pitch angle -180.0 <= The < 180.0 deg
pfPsiDegyaw angle Psi with range 0.0 <= Psi < 360.0 deg
pfRhoDegthe compass heading angle Rho equals the yaw angle Psi
pfChiDegthe tilt angle from vertical Chi (0 <= Chi <= 180 deg)

Definition at line 564 of file orientation.c.

Referenced by fRun_3DOF_B_BASIC(), fRun_3DOF_G_BASIC(), fRun_3DOF_Y_BASIC(), fRun_6DOF_GB_BASIC(), and fRun_6DOF_GY_KALMAN().

566 {
567  // calculate the roll angle -90.0 <= Phi <= 90.0 deg
568  *pfPhiDeg = fasin_deg(R[CHX][CHZ]);
569 
570  // calculate the pitch angle -180.0 <= The < 180.0 deg
571  *pfTheDeg = fatan2_deg(-R[CHY][CHZ], R[CHZ][CHZ]);
572 
573  // map +180 pitch onto the functionally equivalent -180 deg pitch
574  if (*pfTheDeg == 180.0F)
575  {
576  *pfTheDeg = -180.0F;
577  }
578 
579  // calculate the yaw (compass) angle 0.0 <= Psi < 360.0 deg
580  if (*pfPhiDeg == 90.0F)
581  {
582  // vertical downwards gimbal lock case
583  *pfPsiDeg = fatan2_deg(R[CHY][CHX], R[CHY][CHY]) - *pfTheDeg;
584  }
585  else if (*pfPhiDeg == -90.0F)
586  {
587  // vertical upwards gimbal lock case
588  *pfPsiDeg = fatan2_deg(R[CHY][CHX], R[CHY][CHY]) + *pfTheDeg;
589  }
590  else
591  {
592  // general case
593  *pfPsiDeg = fatan2_deg(-R[CHX][CHY], R[CHX][CHX]);
594  }
595 
596  // map yaw angle Psi onto range 0.0 <= Psi < 360.0 deg
597  if (*pfPsiDeg < 0.0F)
598  {
599  *pfPsiDeg += 360.0F;
600  }
601 
602  // check for rounding errors mapping small negative angle to 360 deg
603  if (*pfPsiDeg >= 360.0F)
604  {
605  *pfPsiDeg = 0.0F;
606  }
607 
608  // the compass heading angle Rho equals the yaw angle Psi
609  // this definition is compliant with Motorola Xoom tablet behavior
610  *pfRhoDeg = *pfPsiDeg;
611 
612  // calculate the tilt angle from vertical Chi (0 <= Chi <= 180 deg)
613  *pfChiDeg = facos_deg(R[CHZ][CHZ]);
614 
615  return;
616 }
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:77
float fasin_deg(float x)
#define R
Definition: status.c:48
#define CHZ
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
float facos_deg(float x)
float fatan2_deg(float y, float x)

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void feCompassAndroid ( float  fR[][3],
float *  pfDelta,
float *  pfsinDelta,
float *  pfcosDelta,
float  fBc[],
float  fGc[],
float *  pfmodBc,
float *  pfmodGc 
)

Android: basic 6DOF e-Compass function, computing rotation matrix fR and magnetic inclination angle fDelta.

Parameters
fRcomputed rotation matrix (output)
pfDeltamagnetic inclination angle (output)
pfsinDeltasin of the inclination angle
pfcosDeltacos of the inclination angle
fBccalibrated magnetometer reading (input)
fGccalibrated accelerometer input vector (input)
pfmodBcmodulus of the calibrated magnetic vector
pfmodGcmodulus of the calibrated accelerometer vector

Definition at line 359 of file orientation.c.

Referenced by fInit_6DOF_GB_BASIC(), fInit_9DOF_GBY_KALMAN(), fRun_6DOF_GB_BASIC(), and fRun_6DOF_GY_KALMAN().

361 {
362  // local variables
363  float fmod[3]; // column moduli
364  float fGcdotBc; // dot product of vectors G.Bc
365  float ftmp; // scratch variable
366  int8 i, j; // loop counters
367 
368  // set the inclination angle to zero in case it is not computed later
369  *pfDelta = *pfsinDelta = 0.0F;
370  *pfcosDelta = 1.0F;
371 
372  // place the un-normalized gravity and geomagnetic vectors into the rotation matrix z and y axes
373  for (i = CHX; i <= CHZ; i++)
374  {
375  fR[i][CHZ] = fGc[i];
376  fR[i][CHY] = fBc[i];
377  }
378 
379  // set x vector to vector product of y and z vectors
380  fR[CHX][CHX] = fR[CHY][CHY] * fR[CHZ][CHZ] - fR[CHZ][CHY] * fR[CHY][CHZ];
381  fR[CHY][CHX] = fR[CHZ][CHY] * fR[CHX][CHZ] - fR[CHX][CHY] * fR[CHZ][CHZ];
382  fR[CHZ][CHX] = fR[CHX][CHY] * fR[CHY][CHZ] - fR[CHY][CHY] * fR[CHX][CHZ];
383 
384  // set y vector to vector product of z and x vectors
385  fR[CHX][CHY] = fR[CHY][CHZ] * fR[CHZ][CHX] - fR[CHZ][CHZ] * fR[CHY][CHX];
386  fR[CHY][CHY] = fR[CHZ][CHZ] * fR[CHX][CHX] - fR[CHX][CHZ] * fR[CHZ][CHX];
387  fR[CHZ][CHY] = fR[CHX][CHZ] * fR[CHY][CHX] - fR[CHY][CHZ] * fR[CHX][CHX];
388 
389  // calculate the rotation matrix column moduli
390  fmod[CHX] = sqrtf(fR[CHX][CHX] * fR[CHX][CHX] + fR[CHY][CHX] * fR[CHY][CHX] + fR[CHZ][CHX] * fR[CHZ][CHX]);
391  fmod[CHY] = sqrtf(fR[CHX][CHY] * fR[CHX][CHY] + fR[CHY][CHY] * fR[CHY][CHY] + fR[CHZ][CHY] * fR[CHZ][CHY]);
392  fmod[CHZ] = sqrtf(fR[CHX][CHZ] * fR[CHX][CHZ] + fR[CHY][CHZ] * fR[CHY][CHZ] + fR[CHZ][CHZ] * fR[CHZ][CHZ]);
393 
394  // normalize the rotation matrix columns
395  if (!((fmod[CHX] == 0.0F) || (fmod[CHY] == 0.0F) || (fmod[CHZ] == 0.0F)))
396  {
397  // loop over columns j
398  for (j = CHX; j <= CHZ; j++)
399  {
400  ftmp = 1.0F / fmod[j];
401  // loop over rows i
402  for (i = CHX; i <= CHZ; i++)
403  {
404  // normalize by the column modulus
405  fR[i][j] *= ftmp;
406  }
407  }
408  }
409  else
410  {
411  // no solution is possible so set rotation to identity matrix
412  f3x3matrixAeqI(fR);
413  return;
414  }
415 
416  // compute the geomagnetic inclination angle (deg)
417  *pfmodGc = fmod[CHZ];
418  *pfmodBc = sqrtf(fBc[CHX] * fBc[CHX] + fBc[CHY] * fBc[CHY] + fBc[CHZ] * fBc[CHZ]);
419  fGcdotBc = fGc[CHX] * fBc[CHX] + fGc[CHY] * fBc[CHY] + fGc[CHZ] * fBc[CHZ];
420  if (!((*pfmodGc == 0.0F) || (*pfmodBc == 0.0F)))
421  {
422  *pfsinDelta = -fGcdotBc / (*pfmodGc * *pfmodBc);
423  *pfcosDelta = sqrtf(1.0F - *pfsinDelta * *pfsinDelta);
424  *pfDelta = fasin_deg(*pfsinDelta);
425  }
426 
427  return;
428 }
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:77
float fasin_deg(float x)
#define CHZ
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
void f3x3matrixAeqI(float A[][3])
function sets the 3x3 matrix A to the identity matrix
Definition: matrix.c:45
int8_t int8
Definition: sensor_fusion.h:55

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void feCompassNED ( float  fR[][3],
float *  pfDelta,
float *  pfsinDelta,
float *  pfcosDelta,
float  fBc[],
float  fGc[],
float *  pfmodBc,
float *  pfmodGc 
)

NED: basic 6DOF e-Compass function, computing rotation matrix fR and magnetic inclination angle fDelta.

Parameters
fRcomputed rotation matrix (output)
pfDeltamagnetic inclination angle (output)
pfsinDeltasin of the inclination angle
pfcosDeltacos of the inclination angle
fBccalibrated magnetometer vector (input)
fGccalibrated accelerometer input vector (input)
pfmodBcmodulus of the calibrated magnetic vector
pfmodGcmodulus of the calibrated accelerometer vector

Definition at line 286 of file orientation.c.

Referenced by fInit_6DOF_GB_BASIC(), fInit_9DOF_GBY_KALMAN(), fRun_6DOF_GB_BASIC(), and fRun_6DOF_GY_KALMAN().

287 {
288  // local variables
289  float fmod[3]; // column moduli
290  float fGcdotBc; // dot product of vectors G.Bc
291  float ftmp; // scratch variable
292  int8 i, j; // loop counters
293 
294  // set the inclination angle to zero in case it is not computed later
295  *pfDelta = *pfsinDelta = 0.0F;
296  *pfcosDelta = 1.0F;
297 
298  // place the un-normalized gravity and geomagnetic vectors into the rotation matrix z and x axes
299  for (i = CHX; i <= CHZ; i++)
300  {
301  fR[i][CHZ] = fGc[i];
302  fR[i][CHX] = fBc[i];
303  }
304 
305  // set y vector to vector product of z and x vectors
306  fR[CHX][CHY] = fR[CHY][CHZ] * fR[CHZ][CHX] - fR[CHZ][CHZ] * fR[CHY][CHX];
307  fR[CHY][CHY] = fR[CHZ][CHZ] * fR[CHX][CHX] - fR[CHX][CHZ] * fR[CHZ][CHX];
308  fR[CHZ][CHY] = fR[CHX][CHZ] * fR[CHY][CHX] - fR[CHY][CHZ] * fR[CHX][CHX];
309 
310  // set x vector to vector product of y and z vectors
311  fR[CHX][CHX] = fR[CHY][CHY] * fR[CHZ][CHZ] - fR[CHZ][CHY] * fR[CHY][CHZ];
312  fR[CHY][CHX] = fR[CHZ][CHY] * fR[CHX][CHZ] - fR[CHX][CHY] * fR[CHZ][CHZ];
313  fR[CHZ][CHX] = fR[CHX][CHY] * fR[CHY][CHZ] - fR[CHY][CHY] * fR[CHX][CHZ];
314 
315  // calculate the rotation matrix column moduli
316  fmod[CHX] = sqrtf(fR[CHX][CHX] * fR[CHX][CHX] + fR[CHY][CHX] * fR[CHY][CHX] + fR[CHZ][CHX] * fR[CHZ][CHX]);
317  fmod[CHY] = sqrtf(fR[CHX][CHY] * fR[CHX][CHY] + fR[CHY][CHY] * fR[CHY][CHY] + fR[CHZ][CHY] * fR[CHZ][CHY]);
318  fmod[CHZ] = sqrtf(fR[CHX][CHZ] * fR[CHX][CHZ] + fR[CHY][CHZ] * fR[CHY][CHZ] + fR[CHZ][CHZ] * fR[CHZ][CHZ]);
319 
320  // normalize the rotation matrix columns
321  if (!((fmod[CHX] == 0.0F) || (fmod[CHY] == 0.0F) || (fmod[CHZ] == 0.0F)))
322  {
323  // loop over columns j
324  for (j = CHX; j <= CHZ; j++)
325  {
326  ftmp = 1.0F / fmod[j];
327  // loop over rows i
328  for (i = CHX; i <= CHZ; i++)
329  {
330  // normalize by the column modulus
331  fR[i][j] *= ftmp;
332  }
333  }
334  }
335  else
336  {
337  // no solution is possible so set rotation to identity matrix
338  f3x3matrixAeqI(fR);
339  return;
340  }
341 
342  // compute the geomagnetic inclination angle (deg)
343  *pfmodGc = fmod[CHZ];
344  *pfmodBc = sqrtf(fBc[CHX] * fBc[CHX] + fBc[CHY] * fBc[CHY] + fBc[CHZ] * fBc[CHZ]);
345  fGcdotBc = fGc[CHX] * fBc[CHX] + fGc[CHY] * fBc[CHY] + fGc[CHZ] * fBc[CHZ];
346  if (!((*pfmodGc == 0.0F) || (*pfmodBc == 0.0F)))
347  {
348  *pfsinDelta = fGcdotBc / (*pfmodGc * *pfmodBc);
349  *pfcosDelta = sqrtf(1.0F - *pfsinDelta * *pfsinDelta);
350  *pfDelta = fasin_deg(*pfsinDelta);
351  }
352 
353  return;
354 }
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:77
float fasin_deg(float x)
#define CHZ
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
void f3x3matrixAeqI(float A[][3])
function sets the 3x3 matrix A to the identity matrix
Definition: matrix.c:45
int8_t int8
Definition: sensor_fusion.h:55

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void feCompassWin8 ( float  fR[][3],
float *  pfDelta,
float *  pfsinDelta,
float *  pfcosDelta,
float  fBc[],
float  fGc[],
float *  pfmodBc,
float *  pfmodGc 
)

Win8: basic 6DOF e-Compass function, computing rotation matrix fR and magnetic inclination angle fDelta.

Parameters
fRcomputed rotation matrix (output)
pfDeltamagnetic inclination angle (output)
pfsinDeltasin of the inclination angle
pfcosDeltacos of the inclination angle
fBccalibrated magnetometer reading (input)
fGccalibrated accelerometer input vector (input)
pfmodBcmodulus of the calibrated magnetic vector
pfmodGcmodulus of the calibrated accelerometer vector

Definition at line 433 of file orientation.c.

Referenced by fInit_6DOF_GB_BASIC(), fInit_9DOF_GBY_KALMAN(), fRun_6DOF_GB_BASIC(), and fRun_6DOF_GY_KALMAN().

435 {
436  // local variables
437  float fmod[3]; // column moduli
438  float fGcdotBc; // dot product of vectors G.Bc
439  float ftmp; // scratch variable
440  int8 i, j; // loop counters
441 
442  // set the inclination angle to zero in case it is not computed later
443  *pfDelta = *pfsinDelta = 0.0F;
444  *pfcosDelta = 1.0F;
445 
446  // place the negated un-normalized gravity and un-normalized geomagnetic vectors into the rotation matrix z and y axes
447  for (i = CHX; i <= CHZ; i++)
448  {
449  fR[i][CHZ] = -fGc[i];
450  fR[i][CHY] = fBc[i];
451  }
452 
453  // set x vector to vector product of y and z vectors
454  fR[CHX][CHX] = fR[CHY][CHY] * fR[CHZ][CHZ] - fR[CHZ][CHY] * fR[CHY][CHZ];
455  fR[CHY][CHX] = fR[CHZ][CHY] * fR[CHX][CHZ] - fR[CHX][CHY] * fR[CHZ][CHZ];
456  fR[CHZ][CHX] = fR[CHX][CHY] * fR[CHY][CHZ] - fR[CHY][CHY] * fR[CHX][CHZ];
457 
458  // set y vector to vector product of z and x vectors
459  fR[CHX][CHY] = fR[CHY][CHZ] * fR[CHZ][CHX] - fR[CHZ][CHZ] * fR[CHY][CHX];
460  fR[CHY][CHY] = fR[CHZ][CHZ] * fR[CHX][CHX] - fR[CHX][CHZ] * fR[CHZ][CHX];
461  fR[CHZ][CHY] = fR[CHX][CHZ] * fR[CHY][CHX] - fR[CHY][CHZ] * fR[CHX][CHX];
462 
463  // calculate the rotation matrix column moduli
464  fmod[CHX] = sqrtf(fR[CHX][CHX] * fR[CHX][CHX] + fR[CHY][CHX] * fR[CHY][CHX] + fR[CHZ][CHX] * fR[CHZ][CHX]);
465  fmod[CHY] = sqrtf(fR[CHX][CHY] * fR[CHX][CHY] + fR[CHY][CHY] * fR[CHY][CHY] + fR[CHZ][CHY] * fR[CHZ][CHY]);
466  fmod[CHZ] = sqrtf(fR[CHX][CHZ] * fR[CHX][CHZ] + fR[CHY][CHZ] * fR[CHY][CHZ] + fR[CHZ][CHZ] * fR[CHZ][CHZ]);
467 
468  // normalize the rotation matrix columns
469  if (!((fmod[CHX] == 0.0F) || (fmod[CHY] == 0.0F) || (fmod[CHZ] == 0.0F)))
470  {
471  // loop over columns j
472  for (j = CHX; j <= CHZ; j++)
473  {
474  ftmp = 1.0F / fmod[j];
475  // loop over rows i
476  for (i = CHX; i <= CHZ; i++)
477  {
478  // normalize by the column modulus
479  fR[i][j] *= ftmp;
480  }
481  }
482  }
483  else
484  {
485  // no solution is possible so set rotation to identity matrix
486  f3x3matrixAeqI(fR);
487  return;
488  }
489 
490  // compute the geomagnetic inclination angle (deg)
491  *pfmodGc = fmod[CHZ];
492  *pfmodBc = sqrtf(fBc[CHX] * fBc[CHX] + fBc[CHY] * fBc[CHY] + fBc[CHZ] * fBc[CHZ]);
493  fGcdotBc = fGc[CHX] * fBc[CHX] + fGc[CHY] * fBc[CHY] + fGc[CHZ] * fBc[CHZ];
494  if (!((*pfmodGc == 0.0F) || (*pfmodBc == 0.0F)))
495  {
496  *pfsinDelta = fGcdotBc / (*pfmodGc * *pfmodBc);
497  *pfcosDelta = sqrtf(1.0F - *pfsinDelta * *pfsinDelta);
498  *pfDelta = fasin_deg(*pfsinDelta);
499  }
500 
501  return;
502 }
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:77
float fasin_deg(float x)
#define CHZ
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
void f3x3matrixAeqI(float A[][3])
function sets the 3x3 matrix A to the identity matrix
Definition: matrix.c:45
int8_t int8
Definition: sensor_fusion.h:55

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void fLPFOrientationQuaternion ( Quaternion pq,
Quaternion pLPq,
float  flpf,
float  fdeltat,
float  fOmega[] 
)

function low pass filters an orientation quaternion and computes virtual gyro rotation rate

Definition at line 912 of file orientation.c.

Referenced by fRun_3DOF_B_BASIC(), fRun_3DOF_G_BASIC(), and fRun_6DOF_GB_BASIC().

913 {
914  // local variables
915  Quaternion fdeltaq; // delta rotation quaternion
916  float rvecdeg[3]; // rotation vector (deg)
917  float ftmp; // scratch variable
918 
919  // set fdeltaq to the delta rotation quaternion conjg(fLPq[n-1) . fqn
920  fdeltaq = qconjgAxB(pLPq, pq);
921  if (fdeltaq.q0 < 0.0F)
922  {
923  fdeltaq.q0 = -fdeltaq.q0;
924  fdeltaq.q1 = -fdeltaq.q1;
925  fdeltaq.q2 = -fdeltaq.q2;
926  fdeltaq.q3 = -fdeltaq.q3;
927  }
928 
929  // set ftmp to a scaled value which equals flpf in the limit of small rotations (q0=1)
930  // but which rises to 1 (all pass) as the delta rotation angle increases (q0 tends to zero)
931  ftmp = flpf + (1.0F - flpf) * sqrtf(fabs(1.0F - fdeltaq.q0 * fdeltaq.q0));
932 
933  // scale the vector component of the delta rotation quaternion by the corrected lpf value
934  // and re-compute the scalar component q0 to ensure normalization
935  fdeltaq.q1 *= ftmp;
936  fdeltaq.q2 *= ftmp;
937  fdeltaq.q3 *= ftmp;
938  fdeltaq.q0 = sqrtf(fabsf(1.0F - fdeltaq.q1 * fdeltaq.q1 - fdeltaq.q2 * fdeltaq.q2 - fdeltaq.q3 * fdeltaq.q3));
939 
940  // calculate the delta rotation vector from fdeltaq and the virtual gyro angular velocity (deg/s)
941  fRotationVectorDegFromQuaternion(&fdeltaq, rvecdeg);
942  ftmp = 1.0F / fdeltat;
943  fOmega[CHX] = rvecdeg[CHX] * ftmp;
944  fOmega[CHY] = rvecdeg[CHY] * ftmp;
945  fOmega[CHZ] = rvecdeg[CHZ] * ftmp;
946 
947  // set LPq[n] = LPq[n-1] . deltaq[n]
948  qAeqAxB(pLPq, &fdeltaq);
949 
950  // renormalize the low pass filtered quaternion to prevent error accumulation.
951  // the renormalization function also ensures that q0 is non-negative
952  fqAeqNormqA(pLPq);
953 
954  return;
955 }
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:77
float q0
scalar component
Definition: orientation.h:39
float q3
z vector component
Definition: orientation.h:42
Quaternion qconjgAxB(const Quaternion *pqA, const Quaternion *pqB)
function compute the quaternion product conjg(qA) * qB
Definition: orientation.c:986
quaternion structure definition
Definition: orientation.h:37
#define CHZ
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
void fqAeqNormqA(Quaternion *pqA)
function normalizes a rotation quaternion and ensures q0 is non-negative
Definition: orientation.c:999
void fRotationVectorDegFromQuaternion(Quaternion *pq, float rvecdeg[])
computes rotation vector (deg) from rotation quaternion
Definition: orientation.c:862
float q2
y vector component
Definition: orientation.h:41
void qAeqAxB(Quaternion *pqA, const Quaternion *pqB)
function compute the quaternion product qA = qA * qB
Definition: orientation.c:969
float q1
x vector component
Definition: orientation.h:40

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void fNEDAnglesDegFromRotationMatrix ( float  R[][3],
float *  pfPhiDeg,
float *  pfTheDeg,
float *  pfPsiDeg,
float *  pfRhoDeg,
float *  pfChiDeg 
)

extract the NED angles in degrees from the NED rotation matrix

Parameters
Rrotation matrix input
pfPhiDegoutput: the roll angle range -180.0 <= Phi < 180.0 deg
pfTheDegoutput: the pitch angle -90.0 <= Theta <= 90.0 deg
pfPsiDegoutput: the yaw (compass) angle 0.0 <= Psi < 360.0 deg
pfRhoDegoutput: For NED, the compass heading Rho equals the yaw angle Psi
pfChiDegoutput: the tilt angle from vertical Chi (0 <= Chi <= 180 deg)

Definition at line 508 of file orientation.c.

Referenced by fRun_3DOF_B_BASIC(), fRun_3DOF_G_BASIC(), fRun_3DOF_Y_BASIC(), fRun_6DOF_GB_BASIC(), and fRun_6DOF_GY_KALMAN().

510 {
511  // calculate the pitch angle -90.0 <= Theta <= 90.0 deg
512  *pfTheDeg = fasin_deg(-R[CHX][CHZ]);
513 
514  // calculate the roll angle range -180.0 <= Phi < 180.0 deg
515  *pfPhiDeg = fatan2_deg(R[CHY][CHZ], R[CHZ][CHZ]);
516 
517  // map +180 roll onto the functionally equivalent -180 deg roll
518  if (*pfPhiDeg == 180.0F)
519  {
520  *pfPhiDeg = -180.0F;
521  }
522 
523  // calculate the yaw (compass) angle 0.0 <= Psi < 360.0 deg
524  if (*pfTheDeg == 90.0F)
525  {
526  // vertical upwards gimbal lock case
527  *pfPsiDeg = fatan2_deg(R[CHZ][CHY], R[CHY][CHY]) + *pfPhiDeg;
528  }
529  else if (*pfTheDeg == -90.0F)
530  {
531  // vertical downwards gimbal lock case
532  *pfPsiDeg = fatan2_deg(-R[CHZ][CHY], R[CHY][CHY]) - *pfPhiDeg;
533  }
534  else
535  {
536  // general case
537  *pfPsiDeg = fatan2_deg(R[CHX][CHY], R[CHX][CHX]);
538  }
539 
540  // map yaw angle Psi onto range 0.0 <= Psi < 360.0 deg
541  if (*pfPsiDeg < 0.0F)
542  {
543  *pfPsiDeg += 360.0F;
544  }
545 
546  // check for rounding errors mapping small negative angle to 360 deg
547  if (*pfPsiDeg >= 360.0F)
548  {
549  *pfPsiDeg = 0.0F;
550  }
551 
552  // for NED, the compass heading Rho equals the yaw angle Psi
553  *pfRhoDeg = *pfPsiDeg;
554 
555  // calculate the tilt angle from vertical Chi (0 <= Chi <= 180 deg)
556  *pfChiDeg = facos_deg(R[CHZ][CHZ]);
557 
558  return;
559 }
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:77
float fasin_deg(float x)
#define R
Definition: status.c:48
#define CHZ
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
float facos_deg(float x)
float fatan2_deg(float y, float x)

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void fqAeq1 ( Quaternion pqA)

set a quaternion to the unit quaternion

Definition at line 1034 of file orientation.c.

Referenced by fInit_3DOF_Y_BASIC().

1035 {
1036  pqA->q0 = 1.0F;
1037  pqA->q1 = pqA->q2 = pqA->q3 = 0.0F;
1038 
1039  return;
1040 }
float q0
scalar component
Definition: orientation.h:39
float q3
z vector component
Definition: orientation.h:42
float q2
y vector component
Definition: orientation.h:41
float q1
x vector component
Definition: orientation.h:40

+ Here is the caller graph for this function:

void fqAeqNormqA ( Quaternion pqA)

function normalizes a rotation quaternion and ensures q0 is non-negative

Definition at line 999 of file orientation.c.

Referenced by fLPFOrientationQuaternion(), fQuaternionFromRotationMatrix(), fRun_3DOF_Y_BASIC(), and fRun_6DOF_GY_KALMAN().

1000 {
1001  float fNorm; // quaternion Norm
1002 
1003  // calculate the quaternion Norm
1004  fNorm = sqrtf(pqA->q0 * pqA->q0 + pqA->q1 * pqA->q1 + pqA->q2 * pqA->q2 + pqA->q3 * pqA->q3);
1005  if (fNorm > CORRUPTQUAT)
1006  {
1007  // general case
1008  fNorm = 1.0F / fNorm;
1009  pqA->q0 *= fNorm;
1010  pqA->q1 *= fNorm;
1011  pqA->q2 *= fNorm;
1012  pqA->q3 *= fNorm;
1013  }
1014  else
1015  {
1016  // return with identity quaternion since the quaternion is corrupted
1017  pqA->q0 = 1.0F;
1018  pqA->q1 = pqA->q2 = pqA->q3 = 0.0F;
1019  }
1020 
1021  // correct a negative scalar component if the function was called with negative q0
1022  if (pqA->q0 < 0.0F)
1023  {
1024  pqA->q0 = -pqA->q0;
1025  pqA->q1 = -pqA->q1;
1026  pqA->q2 = -pqA->q2;
1027  pqA->q3 = -pqA->q3;
1028  }
1029 
1030  return;
1031 }
float q0
scalar component
Definition: orientation.h:39
float q3
z vector component
Definition: orientation.h:42
#define CORRUPTQUAT
Definition: orientation.c:52
float q2
y vector component
Definition: orientation.h:41
float q1
x vector component
Definition: orientation.h:40

+ Here is the caller graph for this function:

void fQuaternionFromRotationMatrix ( float  R[][3],
Quaternion pq 
)

compute the orientation quaternion from a 3x3 rotation matrix

Parameters
RRotation matrix (input)
pqQuaternion (output)

Definition at line 781 of file orientation.c.

Referenced by fInit_3DOF_B_BASIC(), fInit_3DOF_G_BASIC(), fInit_6DOF_GB_BASIC(), fInit_6DOF_GY_KALMAN(), fInit_9DOF_GBY_KALMAN(), fRun_3DOF_B_BASIC(), fRun_3DOF_G_BASIC(), fRun_6DOF_GB_BASIC(), and fRun_6DOF_GY_KALMAN().

782 {
783  float fq0sq; // q0^2
784  float recip4q0; // 1/4q0
785 
786  // get q0^2 and q0
787  fq0sq = 0.25F * (1.0F + R[CHX][CHX] + R[CHY][CHY] + R[CHZ][CHZ]);
788  pq->q0 = sqrtf(fabsf(fq0sq));
789 
790  // normal case when q0 is not small meaning rotation angle not near 180 deg
791  if (pq->q0 > SMALLQ0)
792  {
793  // calculate q1 to q3
794  recip4q0 = 0.25F / pq->q0;
795  pq->q1 = recip4q0 * (R[CHY][CHZ] - R[CHZ][CHY]);
796  pq->q2 = recip4q0 * (R[CHZ][CHX] - R[CHX][CHZ]);
797  pq->q3 = recip4q0 * (R[CHX][CHY] - R[CHY][CHX]);
798  } // end of general case
799  else
800  {
801  // special case of near 180 deg corresponds to nearly symmetric matrix
802  // which is not numerically well conditioned for division by small q0
803  // instead get absolute values of q1 to q3 from leading diagonal
804  pq->q1 = sqrtf(fabsf(0.5F + 0.5F * R[CHX][CHX] - fq0sq));
805  pq->q2 = sqrtf(fabsf(0.5F + 0.5F * R[CHY][CHY] - fq0sq));
806  pq->q3 = sqrtf(fabsf(0.5F + 0.5F * R[CHZ][CHZ] - fq0sq));
807 
808  // correct the signs of q1 to q3 by examining the signs of differenced off-diagonal terms
809  if ((R[CHY][CHZ] - R[CHZ][CHY]) < 0.0F) pq->q1 = -pq->q1;
810  if ((R[CHZ][CHX] - R[CHX][CHZ]) < 0.0F) pq->q2 = -pq->q2;
811  if ((R[CHX][CHY] - R[CHY][CHX]) < 0.0F) pq->q3 = -pq->q3;
812  } // end of special case
813 
814  // ensure that the resulting quaternion is normalized even if the input rotation matrix was not
815  fqAeqNormqA(pq);
816 
817 
818  return;
819 }
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:77
float q0
scalar component
Definition: orientation.h:39
float q3
z vector component
Definition: orientation.h:42
#define R
Definition: status.c:48
#define CHZ
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
void fqAeqNormqA(Quaternion *pqA)
function normalizes a rotation quaternion and ensures q0 is non-negative
Definition: orientation.c:999
#define SMALLQ0
Definition: orientation.c:51
float q2
y vector component
Definition: orientation.h:41
float q1
x vector component
Definition: orientation.h:40

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void fQuaternionFromRotationVectorDeg ( Quaternion pq,
const float  rvecdeg[],
float  fscaling 
)

computes normalized rotation quaternion from a rotation vector (deg)

Parameters
pqquaternion (output)
rvecdegrotation vector in degrees
fscalingdelta Time

Definition at line 713 of file orientation.c.

Referenced by fRun_3DOF_Y_BASIC(), and fRun_6DOF_GY_KALMAN().

714 {
715  float fetadeg; // rotation angle (deg)
716  float fetarad; // rotation angle (rad)
717  float fetarad2; // eta (rad)^2
718  float fetarad4; // eta (rad)^4
719  float sinhalfeta; // sin(eta/2)
720  float fvecsq; // q1^2+q2^2+q3^2
721  float ftmp; // scratch variable
722 
723  // compute the scaled rotation angle eta (deg) which can be both positve or negative
724  fetadeg = fscaling * sqrtf(rvecdeg[CHX] * rvecdeg[CHX] + rvecdeg[CHY] * rvecdeg[CHY] + rvecdeg[CHZ] * rvecdeg[CHZ]);
725  fetarad = fetadeg * FPIOVER180;
726  fetarad2 = fetarad * fetarad;
727 
728  // calculate the sine and cosine using small angle approximations or exact
729  // angles under sqrt(0.02)=0.141 rad is 8.1 deg and 1620 deg/s (=936deg/s in 3 axes) at 200Hz and 405 deg/s at 50Hz
730  if (fetarad2 <= 0.02F)
731  {
732  // use MacLaurin series up to and including third order
733  sinhalfeta = fetarad * (0.5F - ONEOVER48 * fetarad2);
734  }
735  else if (fetarad2 <= 0.06F)
736  {
737  // use MacLaurin series up to and including fifth order
738  // angles under sqrt(0.06)=0.245 rad is 14.0 deg and 2807 deg/s (=1623deg/s in 3 axes) at 200Hz and 703 deg/s at 50Hz
739  fetarad4 = fetarad2 * fetarad2;
740  sinhalfeta = fetarad * (0.5F - ONEOVER48 * fetarad2 + ONEOVER3840 * fetarad4);
741  }
742  else
743  {
744  // use exact calculation
745  sinhalfeta = (float)sinf(0.5F * fetarad);
746  }
747 
748  // compute the vector quaternion components q1, q2, q3
749  if (fetadeg != 0.0F)
750  {
751  // general case with non-zero rotation angle
752  ftmp = fscaling * sinhalfeta / fetadeg;
753  pq->q1 = rvecdeg[CHX] * ftmp; // q1 = nx * sin(eta/2)
754  pq->q2 = rvecdeg[CHY] * ftmp; // q2 = ny * sin(eta/2)
755  pq->q3 = rvecdeg[CHZ] * ftmp; // q3 = nz * sin(eta/2)
756  }
757  else
758  {
759  // zero rotation angle giving zero vector component
760  pq->q1 = pq->q2 = pq->q3 = 0.0F;
761  }
762 
763  // compute the scalar quaternion component q0 by explicit normalization
764  // taking care to avoid rounding errors giving negative operand to sqrt
765  fvecsq = pq->q1 * pq->q1 + pq->q2 * pq->q2 + pq->q3 * pq->q3;
766  if (fvecsq <= 1.0F)
767  {
768  // normal case
769  pq->q0 = sqrtf(1.0F - fvecsq);
770  }
771  else
772  {
773  // rounding errors are present
774  pq->q0 = 0.0F;
775  }
776 
777  return;
778 }
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:77
float q0
scalar component
Definition: orientation.h:39
#define FPIOVER180
degrees to radians conversion = pi / 180
Definition: sensor_fusion.h:99
float q3
z vector component
Definition: orientation.h:42
#define CHZ
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
#define ONEOVER3840
1 / 3840
#define ONEOVER48
1 / 48
float q2
y vector component
Definition: orientation.h:41
float q1
x vector component
Definition: orientation.h:40

+ Here is the caller graph for this function:

void fRotationMatrixFromQuaternion ( float  R[][3],
const Quaternion pq 
)

compute the rotation matrix from an orientation quaternion

Parameters
RRotation matrix (output)
pqQuaternion (input)

Definition at line 822 of file orientation.c.

Referenced by fRun_3DOF_B_BASIC(), fRun_3DOF_G_BASIC(), fRun_3DOF_Y_BASIC(), fRun_6DOF_GB_BASIC(), and fRun_6DOF_GY_KALMAN().

823 {
824  float f2q;
825  float f2q0q0, f2q0q1, f2q0q2, f2q0q3;
826  float f2q1q1, f2q1q2, f2q1q3;
827  float f2q2q2, f2q2q3;
828  float f2q3q3;
829 
830  // set f2q to 2*q0 and calculate products
831  f2q = 2.0F * pq->q0;
832  f2q0q0 = f2q * pq->q0;
833  f2q0q1 = f2q * pq->q1;
834  f2q0q2 = f2q * pq->q2;
835  f2q0q3 = f2q * pq->q3;
836  // set f2q to 2*q1 and calculate products
837  f2q = 2.0F * pq->q1;
838  f2q1q1 = f2q * pq->q1;
839  f2q1q2 = f2q * pq->q2;
840  f2q1q3 = f2q * pq->q3;
841  // set f2q to 2*q2 and calculate products
842  f2q = 2.0F * pq->q2;
843  f2q2q2 = f2q * pq->q2;
844  f2q2q3 = f2q * pq->q3;
845  f2q3q3 = 2.0F * pq->q3 * pq->q3;
846 
847  // calculate the rotation matrix assuming the quaternion is normalized
848  R[CHX][CHX] = f2q0q0 + f2q1q1 - 1.0F;
849  R[CHX][CHY] = f2q1q2 + f2q0q3;
850  R[CHX][CHZ] = f2q1q3 - f2q0q2;
851  R[CHY][CHX] = f2q1q2 - f2q0q3;
852  R[CHY][CHY] = f2q0q0 + f2q2q2 - 1.0F;
853  R[CHY][CHZ] = f2q2q3 + f2q0q1;
854  R[CHZ][CHX] = f2q1q3 + f2q0q2;
855  R[CHZ][CHY] = f2q2q3 - f2q0q1;
856  R[CHZ][CHZ] = f2q0q0 + f2q3q3 - 1.0F;
857 
858  return;
859 }
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:77
float q0
scalar component
Definition: orientation.h:39
float q3
z vector component
Definition: orientation.h:42
#define R
Definition: status.c:48
#define CHZ
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
float q2
y vector component
Definition: orientation.h:41
float q1
x vector component
Definition: orientation.h:40

+ Here is the caller graph for this function:

void fRotationVectorDegFromQuaternion ( Quaternion pq,
float  rvecdeg[] 
)

computes rotation vector (deg) from rotation quaternion

Parameters
pqquaternion (input)
rvecdegrotation vector in degrees (output)

Definition at line 862 of file orientation.c.

Referenced by fLPFOrientationQuaternion(), fRun_3DOF_B_BASIC(), fRun_3DOF_G_BASIC(), fRun_3DOF_Y_BASIC(), fRun_6DOF_GB_BASIC(), and fRun_6DOF_GY_KALMAN().

863 {
864  float fetarad; // rotation angle (rad)
865  float fetadeg; // rotation angle (deg)
866  float sinhalfeta; // sin(eta/2)
867  float ftmp; // scratch variable
868 
869  // calculate the rotation angle in the range 0 <= eta < 360 deg
870  if ((pq->q0 >= 1.0F) || (pq->q0 <= -1.0F))
871  {
872  // rotation angle is 0 deg or 2*180 deg = 360 deg = 0 deg
873  fetarad = 0.0F;
874  fetadeg = 0.0F;
875  }
876  else
877  {
878  // general case returning 0 < eta < 360 deg
879  fetarad = 2.0F * acosf(pq->q0);
880  fetadeg = fetarad * F180OVERPI;
881  }
882 
883  // map the rotation angle onto the range -180 deg <= eta < 180 deg
884  if (fetadeg >= 180.0F)
885  {
886  fetadeg -= 360.0F;
887  fetarad = fetadeg * FPIOVER180;
888  }
889 
890  // calculate sin(eta/2) which will be in the range -1 to +1
891  sinhalfeta = (float)sinf(0.5F * fetarad);
892 
893  // calculate the rotation vector (deg)
894  if (sinhalfeta == 0.0F)
895  {
896  // the rotation angle eta is zero and the axis is irrelevant
897  rvecdeg[CHX] = rvecdeg[CHY] = rvecdeg[CHZ] = 0.0F;
898  }
899  else
900  {
901  // general case with non-zero rotation angle
902  ftmp = fetadeg / sinhalfeta;
903  rvecdeg[CHX] = pq->q1 * ftmp;
904  rvecdeg[CHY] = pq->q2 * ftmp;
905  rvecdeg[CHZ] = pq->q3 * ftmp;
906  }
907 
908  return;
909 }
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:77
float q0
scalar component
Definition: orientation.h:39
#define FPIOVER180
degrees to radians conversion = pi / 180
Definition: sensor_fusion.h:99
float q3
z vector component
Definition: orientation.h:42
#define CHZ
#define F180OVERPI
radians to degrees conversion = 180 / pi
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
float q2
y vector component
Definition: orientation.h:41
float q1
x vector component
Definition: orientation.h:40

+ Here is the caller graph for this function:

void fveqconjgquq ( Quaternion pfq,
float  fu[],
float  fv[] 
)

function computes the rotation quaternion that rotates unit vector u onto unit vector v as v=q*.u.q using q = 1/sqrt(2) * {sqrt(1 + u.v) - u x v / sqrt(1 + u.v)}

Definition at line 1044 of file orientation.c.

Referenced by fRun_6DOF_GY_KALMAN().

1045 {
1046  float fuxv[3]; // vector product u x v
1047  float fsqrt1plusudotv; // sqrt(1 + u.v)
1048  float ftmp; // scratch
1049 
1050  // compute sqrt(1 + u.v) and scalar quaternion component q0 (valid for all angles including 180 deg)
1051  fsqrt1plusudotv = sqrtf(fabsf(1.0F + fu[CHX] * fv[CHX] + fu[CHY] * fv[CHY] + fu[CHZ] * fv[CHZ]));
1052  pfq->q0 = ONEOVERSQRT2 * fsqrt1plusudotv;
1053 
1054  // calculate the vector product uxv
1055  fuxv[CHX] = fu[CHY] * fv[CHZ] - fu[CHZ] * fv[CHY];
1056  fuxv[CHY] = fu[CHZ] * fv[CHX] - fu[CHX] * fv[CHZ];
1057  fuxv[CHZ] = fu[CHX] * fv[CHY] - fu[CHY] * fv[CHX];
1058 
1059  // compute the vector component of the quaternion
1060  if (fsqrt1plusudotv != 0.0F)
1061  {
1062  // general case where u and v are not anti-parallel where u.v=-1
1063  ftmp = ONEOVERSQRT2 / fsqrt1plusudotv;
1064  pfq->q1 = -fuxv[CHX] * ftmp;
1065  pfq->q2 = -fuxv[CHY] * ftmp;
1066  pfq->q3 = -fuxv[CHZ] * ftmp;
1067  }
1068  else
1069  {
1070  // degenerate case where u and v are anti-aligned and the 180 deg rotation quaternion is not uniquely defined.
1071  // first calculate the un-normalized vector component (the scalar component q0 is already set to zero)
1072  pfq->q1 = fu[CHY] - fu[CHZ];
1073  pfq->q2 = fu[CHZ] - fu[CHX];
1074  pfq->q3 = fu[CHX] - fu[CHY];
1075  // and normalize the quaternion for this case checking for fu[CHX]=fu[CHY]=fuCHZ] where q1=q2=q3=0.
1076  ftmp = sqrtf(fabsf(pfq->q1 * pfq->q1 + pfq->q2 * pfq->q2 + pfq->q3 * pfq->q3));
1077  if (ftmp != 0.0F)
1078  {
1079  // normal case where all three components of fu (and fv=-fu) are not equal
1080  ftmp = 1.0F / ftmp;
1081  pfq->q1 *= ftmp;
1082  pfq->q2 *= ftmp;
1083  pfq->q3 *= ftmp;
1084  }
1085  else
1086  {
1087  // final case where the three entries are equal but since the vectors are known to be normalized
1088  // the vector u must be 1/root(3)*{1, 1, 1} or -1/root(3)*{1, 1, 1} so simply set the
1089  // rotation vector to 1/root(2)*{1, -1, 0} to cover both cases
1090  pfq->q1 = ONEOVERSQRT2;
1091  pfq->q2 = -ONEOVERSQRT2;
1092  pfq->q3 = 0.0F;
1093  }
1094  }
1095 
1096  return;
1097 }
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:77
#define ONEOVERSQRT2
1/sqrt(2)
float q0
scalar component
Definition: orientation.h:39
float q3
z vector component
Definition: orientation.h:42
#define CHZ
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
float q2
y vector component
Definition: orientation.h:41
float q1
x vector component
Definition: orientation.h:40

+ Here is the caller graph for this function:

void fWin8AnglesDegFromRotationMatrix ( float  R[][3],
float *  pfPhiDeg,
float *  pfTheDeg,
float *  pfPsiDeg,
float *  pfRhoDeg,
float *  pfChiDeg 
)

extract the Windows 8 angles in degrees from the Windows 8 rotation matrix

Parameters
Rrotation matrix input
pfPhiDegthe roll angle -90.0 <= Phi <= 90.0 deg
pfTheDegpitch angle Theta in the range -180.0 <= The < 180.0 deg
pfPsiDegyaw angle Psi in range 0.0 <= Psi < 360.0 deg
pfRhoDegthe compass angle Rho = 360 - Psi
pfChiDegtilt angle from vertical Chi (0 <= Chi <= 180 deg)

Definition at line 621 of file orientation.c.

Referenced by fRun_3DOF_B_BASIC(), fRun_3DOF_G_BASIC(), fRun_3DOF_Y_BASIC(), fRun_6DOF_GB_BASIC(), and fRun_6DOF_GY_KALMAN().

623 {
624  // calculate the roll angle -90.0 <= Phi <= 90.0 deg
625  if (R[CHZ][CHZ] == 0.0F)
626  {
627  if (R[CHX][CHZ] >= 0.0F)
628  {
629  // tan(phi) is -infinity
630  *pfPhiDeg = -90.0F;
631  }
632  else
633  {
634  // tan(phi) is +infinity
635  *pfPhiDeg = 90.0F;
636  }
637  }
638  else
639  {
640  // general case
641  *pfPhiDeg = fatan_deg(-R[CHX][CHZ] / R[CHZ][CHZ]);
642  }
643 
644  // first calculate the pitch angle The in the range -90.0 <= The <= 90.0 deg
645  *pfTheDeg = fasin_deg(R[CHY][CHZ]);
646 
647  // use R[CHZ][CHZ]=cos(Phi)*cos(The) to correct the quadrant of The remembering
648  // cos(Phi) is non-negative so that cos(The) has the same sign as R[CHZ][CHZ].
649  if (R[CHZ][CHZ] < 0.0F)
650  {
651  // wrap The around +90 deg and -90 deg giving result 90 to 270 deg
652  *pfTheDeg = 180.0F - *pfTheDeg;
653  }
654 
655  // map the pitch angle The to the range -180.0 <= The < 180.0 deg
656  if (*pfTheDeg >= 180.0F)
657  {
658  *pfTheDeg -= 360.0F;
659  }
660 
661  // calculate the yaw angle Psi
662  if (*pfTheDeg == 90.0F)
663  {
664  // vertical upwards gimbal lock case: -270 <= Psi < 90 deg
665  *pfPsiDeg = fatan2_deg(R[CHX][CHY], R[CHX][CHX]) - *pfPhiDeg;
666  }
667  else if (*pfTheDeg == -90.0F)
668  {
669  // vertical downwards gimbal lock case: -270 <= Psi < 90 deg
670  *pfPsiDeg = fatan2_deg(R[CHX][CHY], R[CHX][CHX]) + *pfPhiDeg;
671  }
672  else
673  {
674  // general case: -180 <= Psi < 180 deg
675  *pfPsiDeg = fatan2_deg(-R[CHY][CHX], R[CHY][CHY]);
676 
677  // correct the quadrant for Psi using the value of The (deg) to give -180 <= Psi < 380 deg
678  if (fabsf(*pfTheDeg) >= 90.0F)
679  {
680  *pfPsiDeg += 180.0F;
681  }
682  }
683 
684  // map yaw angle Psi onto range 0.0 <= Psi < 360.0 deg
685  if (*pfPsiDeg < 0.0F)
686  {
687  *pfPsiDeg += 360.0F;
688  }
689 
690  // check for any rounding error mapping small negative angle to 360 deg
691  if (*pfPsiDeg >= 360.0F)
692  {
693  *pfPsiDeg = 0.0F;
694  }
695 
696  // compute the compass angle Rho = 360 - Psi
697  *pfRhoDeg = 360.0F - *pfPsiDeg;
698 
699  // check for rounding errors mapping small negative angle to 360 deg and zero degree case
700  if (*pfRhoDeg >= 360.0F)
701  {
702  *pfRhoDeg = 0.0F;
703  }
704 
705  // calculate the tilt angle from vertical Chi (0 <= Chi <= 180 deg)
706  *pfChiDeg = facos_deg(R[CHZ][CHZ]);
707 
708  return;
709 }
float fatan_deg(float x)
#define CHY
Used to access Y-channel entries in various data data structures.
Definition: sensor_fusion.h:77
float fasin_deg(float x)
#define R
Definition: status.c:48
#define CHZ
#define CHX
Used to access X-channel entries in various data data structures.
Definition: sensor_fusion.h:76
float facos_deg(float x)
float fatan2_deg(float y, float x)

+ Here is the call graph for this function:

+ Here is the caller graph for this function:

void qAeqAxB ( Quaternion pqA,
const Quaternion pqB 
)

function compute the quaternion product qA = qA * qB

Definition at line 969 of file orientation.c.

Referenced by ApplyPerturbation(), fLPFOrientationQuaternion(), fRun_3DOF_Y_BASIC(), and fRun_6DOF_GY_KALMAN().

970 {
971  Quaternion qProd;
972 
973  // perform the quaternion product
974  qProd.q0 = pqA->q0 * pqB->q0 - pqA->q1 * pqB->q1 - pqA->q2 * pqB->q2 - pqA->q3 * pqB->q3;
975  qProd.q1 = pqA->q0 * pqB->q1 + pqA->q1 * pqB->q0 + pqA->q2 * pqB->q3 - pqA->q3 * pqB->q2;
976  qProd.q2 = pqA->q0 * pqB->q2 - pqA->q1 * pqB->q3 + pqA->q2 * pqB->q0 + pqA->q3 * pqB->q1;
977  qProd.q3 = pqA->q0 * pqB->q3 + pqA->q1 * pqB->q2 - pqA->q2 * pqB->q1 + pqA->q3 * pqB->q0;
978 
979  // copy the result back into qA
980  *pqA = qProd;
981 
982  return;
983 }
float q0
scalar component
Definition: orientation.h:39
float q3
z vector component
Definition: orientation.h:42
quaternion structure definition
Definition: orientation.h:37
float q2
y vector component
Definition: orientation.h:41
float q1
x vector component
Definition: orientation.h:40

+ Here is the caller graph for this function:

void qAeqBxC ( Quaternion pqA,
const Quaternion pqB,
const Quaternion pqC 
)

function compute the quaternion product qB * qC

Definition at line 958 of file orientation.c.

Referenced by fRun_6DOF_GY_KALMAN().

959 {
960  pqA->q0 = pqB->q0 * pqC->q0 - pqB->q1 * pqC->q1 - pqB->q2 * pqC->q2 - pqB->q3 * pqC->q3;
961  pqA->q1 = pqB->q0 * pqC->q1 + pqB->q1 * pqC->q0 + pqB->q2 * pqC->q3 - pqB->q3 * pqC->q2;
962  pqA->q2 = pqB->q0 * pqC->q2 - pqB->q1 * pqC->q3 + pqB->q2 * pqC->q0 + pqB->q3 * pqC->q1;
963  pqA->q3 = pqB->q0 * pqC->q3 + pqB->q1 * pqC->q2 - pqB->q2 * pqC->q1 + pqB->q3 * pqC->q0;
964 
965  return;
966 }
float q0
scalar component
Definition: orientation.h:39
float q3
z vector component
Definition: orientation.h:42
float q2
y vector component
Definition: orientation.h:41
float q1
x vector component
Definition: orientation.h:40

+ Here is the caller graph for this function:

Quaternion qconjgAxB ( const Quaternion pqA,
const Quaternion pqB 
)

function compute the quaternion product conjg(qA) * qB

Definition at line 986 of file orientation.c.

Referenced by fLPFOrientationQuaternion().

987 {
988  Quaternion qProd;
989 
990  qProd.q0 = pqA->q0 * pqB->q0 + pqA->q1 * pqB->q1 + pqA->q2 * pqB->q2 + pqA->q3 * pqB->q3;
991  qProd.q1 = pqA->q0 * pqB->q1 - pqA->q1 * pqB->q0 - pqA->q2 * pqB->q3 + pqA->q3 * pqB->q2;
992  qProd.q2 = pqA->q0 * pqB->q2 + pqA->q1 * pqB->q3 - pqA->q2 * pqB->q0 - pqA->q3 * pqB->q1;
993  qProd.q3 = pqA->q0 * pqB->q3 - pqA->q1 * pqB->q2 + pqA->q2 * pqB->q1 - pqA->q3 * pqB->q0;
994 
995  return qProd;
996 }
float q0
scalar component
Definition: orientation.h:39
float q3
z vector component
Definition: orientation.h:42
quaternion structure definition
Definition: orientation.h:37
float q2
y vector component
Definition: orientation.h:41
float q1
x vector component
Definition: orientation.h:40

+ Here is the caller graph for this function: